// 将在这里封装axios, 方面其他方法进行请求调用

// 先进行需要内容的引入
import axios from 'axios'
import type {
  AxiosInstance, AxiosRequestConfig,
  AxiosResponse, InternalAxiosRequestConfig
} from 'axios'

// 定义后端返回的统一数据结构, 泛型接口，定义T -> 任意类型的data数据
export interface ApiResponse<T = any> {
  code: number // 响应码
  data: T // 后端给的数据
  message: string // 响应信息
  success: boolean // 响应成功与否
}

// 扩展 AxiosRequestConfig 以支持自定义配置
export interface RequestOptions extends AxiosRequestConfig {
  // 是否显示错误提示
  showError?: boolean
  // 是否显示成功提示
  showSuccess?: boolean
}

class HttpClient {
  // 创建axios实例
  private instance: AxiosInstance

  // 创建构造器，通过传入的url进行axios.create，并设置超时时间
  constructor(baseURL: string) {
    this.instance = axios.create({
      baseURL,
      timeout: 10000 // 设置超时时间为10s
    })

    this.setupInterceptors() // 调用拦截器
  }

  // 拦截器
  private setupInterceptors() {

    // 请求拦截器
    this.instance.interceptors.request.use(
      // 请求拦截器，添加token
      (config: InternalAxiosRequestConfig) => {
        // 从本地存储获取 token
        const token = localStorage.getItem('token')
        // 如果token存在，放在header中的Bearer中
        if (token && config.headers) {
          config.headers.Authorization = `Bearer ${token}`
        }
        return config
      },
      // 错误处理，直接Promise中的reject
      (error) => {
        return Promise.reject(error)
      }
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      // 响应拦截器，根据业务逻辑处理响应
      (response: AxiosResponse<ApiResponse>) => {
        // 响应数据
        const {data} = response
        // 如果调用成功，返回相应数据中的data
        // 根据业务代码处理响应
        if (data.code === 200) {
          return data.data
        } else {
          // 业务逻辑错误
          return Promise.reject(new Error(data.message || 'Error'))
        }
      },
      // 错误处理，直接Promise中的reject
      (error) => {
        // 根据error响应错误信息获取
        let message = this.getMessageFromError(error);
        // 返回Promise中的reject
        return Promise.reject(new Error(message))
      }
    )
  }

  // 获取错误信息
  private getMessageFromError(error: any) {
    // HTTP 状态码错误处理
    let message: string
    if (error.response) {
      switch (error.response.status) {
        case 401:
          message = '请先登录'
          // 跳转到登录页
          break
        case 403:
          message = '没有权限'
          break
        case 404:
          message = '资源不存在'
          break
        case 500:
          message = '服务器错误'
          break
        default:
          message = error.response.data?.message || '请求失败'
      }
    } else {
      message = '网络连接失败'
    }
    return message
  }

  // 请求
  public async request<T = any>(options: RequestOptions): Promise<T> {
    return this.instance.request(options)
  }

  // get请求
  public get<T = any>(url: string, config?: RequestOptions): Promise<T> {
    return this.instance.get(url, config)
  }

  // post请求
  // T -> 泛型接口，定义T -> 响应数据中的data数据
  // url -> 请求地址
  // data -> 请求数据
  // config -> 配置项
  // 返回值 -> Promise<T>，对应上面的相应拦截，如果成功返回data中的data数据，如果失败返回错误信息
  public post<T = any>(url: string, data?: any, config?: RequestOptions): Promise<T> {
    return this.instance.post(url, data, config)
  }

  // put请求
  // T -> 泛型接口，定义T -> 响应数据中的data数据
  // url -> 请求地址
  // data -> 请求数据
  // config -> 配置项
  // 返回值 -> Promise<T>，对应上面的相应拦截，如果成功返回data中的data数据，如果失败返回错误信息
  public put<T = any>(url: string, data?: any, config?: RequestOptions): Promise<T> {
    return this.instance.put(url, data, config)
  }

  // delete请求
  // T -> 泛型接口，定义T -> 响应数据中的data数据
  // url -> 请求地址
  // config -> 配置项
  public delete<T = any>(url: string, config?: RequestOptions): Promise<T> {
    return this.instance.delete(url, config)
  }
}

// 创建实例 - 根据后端接口地址
const http = new HttpClient(import.meta.env.VITE_API_BASE_URL)

export default http
